14_01

重载操作符必须具有至少一个class或枚举类型的操作数
重载操作符不保证操作数的求值顺序，例如对&&和||的重载版本不再具有“短路求值”的特性，两个操作数都要进行求值操作，而且不规定操作数的求值顺序
相同点：对于优先级和结合性及操作数的数目都不变

ex14_03

(a)"cobble"=="store"应用了C++语言内置版本的==，比较两个指针；
(b)svec1[0]=svec2[0]应用string版本的重载==；
(c)svec1=svec2应用了vector版本的重载==；
(d)svec1[0]=="stone"应用了string版本的重载==，字符串字面常量被转换为string

ex14_04

(a)%是一个具有对称性的运算符，因此%通常定义为非成员
(b)%=是一个能够改变类对象状态的运算符，因此%=定义为类的成员运算符
(c)++是一个能够改变类独享状态的云算符，因此++定义为类的成员运算符
(d)箭头运算符必须定义为成员运算符
(e)<<通常被定义为非成员运算符
(f)&&通常被定义为非成员运算符
(g)==通常被定义为非成员运算符
(h)调用运算符必须被定义为成员运算符

ex14_05

当时我是编写的book类，代码如下：

#include<iostream>
#include<string>


class Book
{
public:
	Book() = default;
	Book(const std::string &name, const std::string &I, double pr, const std::string &a, const std::string &p)
	{
		BookName = name;
		ISBN = I;
		Price = pr;
		Author = a;
		Publisher = p;
	}
	Book(std::istream &in)
	{
		in >> BookName >> ISBN >> Price >> Author >> Publisher;
	}

private:
	std::string BookName, ISBN, Author, Publisher;
	double Price = 0.0;
};

对其进行修改，可以定义重载的运算符，如ex14_05.h


ex14_06

Sales_data的输出运算符的定义如下：

class Sales_data
{
	friend ostream& operator<<(ostream &os,const Sales_data &item);
	//其他成员
};
ostream operator<<(ostream &os,const Sales_data &item)
{
	
	os<<item.isbn()<<" "<<item.units_sold()<<" "<<item.revenue()<<" "<<item.avg_price();
	return os;
}

ex14_07

String类的输出运算符如下：
 class String
 {
 	public:
		String();
		String(const char *str);
		friend ostream& operator<<(ostream &os,const String &str);
	private:
		char *str;
 };
 
 ostream& operator<<(ostream &os,const String &str)
 {
 	cout<<str;
	return os;
 }
 
 ex14_08
 
 这道例题的解答请参考14_05.cpp

ex14_09

输入运算符从给定输入流中读取对应类型的对象，存入Sales_data的数据成员中，与输出不同，输入通常要进行一些正确定的判定，并进行相应的处理。
Sales_data的输入运算符定义如下：
class Sales_data
{
	friend istream& operator>>(istream &is,Sales_data &item);
};
istream& operator>>(istream &is,Sales_data &item)
{
	double price;
	is>>item.bookNO>>item.units_sold>>price;
	if(is)
	{
		item.revenue=item.units_sold>>price;
	}
	else
	{
		item=Sales_data();
	}
	return is;
}

ex14_10

(a)参数中传入的是Sales_data对象会得到输入的值，其中bookNo、units_sold、price的值分别是0-201-99999-9、10、24.5；
(b)输入错误，参数中传入的Sales_data对象将会得到默认值


ex14_11

重载输入运算符和重载输出运算符的区别就在于重载输入运算符可能会做一些验证工作，但是本题中的这段代码没有进行验证，因此是不正确的
如果输入上一题的(a)组数据，那么程序会正常的执行，得到想要的结果；如过输入上一题的(b)组数据，那么程序虽然也能够执行，但是得到的值是错误的，因为这与预期希望的值是不符合的


ex14_13

可以再为Sales_data类提供一个减法运算符，具体请看ex14_13.h

ex14_14

从头实现operator+的方式与借助operator+=实现的方式相比，在性能上没有优势，在可读性上，operator+=更好，因此，使用operator+=是更好的方式

ex14_21

本题的代码在性能上没有优势，可读性也不好


ex14_29

对于递增和递减运算符来说，无论是前置版本还是后置版本，都会改变对象本来的值，因此不能定义成const的

ex14_31

StrBlobPtr类有两个成员，分别是弱智能指针weak_ptr<vector<string>>和size_t类型的，智能指针类型有自己的拷贝构造函数、赋值运算符和析构函数，size_t是内置类型的，使用默认的拷贝赋值成员，不需要定义特定的拷贝构造函数、赋值运算符和析构函数

ex14_33

一个重载的函数调用运算符可以接受0个或多个运算对象

ex14_41

在C++11中，lambda是通过匿名的函数对象来实现的，因此我们可以把lambda看作是对函数对象在使用方式上进行的简化
当代码需要一个简单的函数，并且这个函数不会在其他地方使用时，就可以使用lambda来实现，此时它所起的作用类似于匿名函数；但是如果这个函数需要多次使用，并且它需要保存某些状态的话，使用函数对象则更合适一些

ex14_42

(a)count_if(vec.begin(),vec.end(),bind2nd(greater<int>(),1024));
(b)find_fi(vec.begin(),vec.end(),bind2nd(not_to_equal_to<string>(),"pooh"));
(c)transform(vec.begin(),vec.end(),vec.begin(),bind2nd(multiplies)<int>(),2));

ex14_43

bool dividedByAll(vector<int> &ivec,int dividend)
{
	return count_if(ivec.begin(),ivec.end(),bindlst(modulus<int>,dividend))==0;
}

ex14_45

如果要转换成string，那么返回值应该是bookNo
如果要转换成double，那么返回值应该是avg_price;

ex14_46

不应该为Sales_data定义上面两种类型的转换运算符，因为对于该类来说，它包含三个数据成员：bookNO,units_sold和revenue，只有这三个数据在一起才是有效的数据。
但是如果定义了这两个类型转换运算符的话，应该把它们声明成explicit的，这样可以防止Sales_data在某些情况下被默认转换成string或double
类型，这有可能导致意料之外的错误

ex14_47

前者将对象转换成const int类型的，在接受const int值的地方才能够使用
后者将对象转换成int值，相对来说更通用一些

ex14_48

我当时编写的是Book类，含有BookName, ISBN, Author, Publisher四个数据成员，
可以为Book类定义bool类型的转换运算符，用来检查4个数据成员是否存在有效值，bool类型转换运算符应该声明成explicit的，因为我们需要显式在条件表达式中使用它

ex14_50

对于int ex1=ldObj;因为ldObj是longdouble类型的，所以首先需要把LongDouble类型转换为int类型，但是longdouble类型并没有定义对相应的类型转换运算符，因此它会尝试使用其他的来进行转换，由operator double()和operator float()都满足要求，但是编译器无法确定哪一个更合适，因此会产生二义性错误
对于float ex2=ldObj;它需要把Longdouble转换成float类型，而我们恰好定义了对应的类型转换运算符，因此只要直接调用operator float()即可

ex14_51

这里会优先调用void calc(int)函数，因为double转换成int是标准类型转换，而转换为LongDouble则是转换为用户自定义类型，实际上是调用了转换构造函数，因此前者有限

ex14_52

对于ld=si+ld:
因为LongDouble不能转换为SmallInt，所以SmallInt的成员operator+和friend operator+都不可行；
由于SmallInt不能转换为LongDouble，LongDouble的成员operator+和非成员operator+也不可行；
因为SmallInt可以转换为int，LongDouble可以转换为float和double，所以内置的operator+(int,float)和operator+(int,double)都可行，所以会产生二义性；


对于ld=ld+si：
因为SmallInt不能转换为double，LongDouble也不能转换成SmallInt，因此SmallInt的成员operator+和两个非成员operator+都不匹配
LongDouble的operator+可行，而且是精确匹配；
SmallInt可以转换成int，LongDouble可以转换成float和double，因此内置的operator+(float,int)和operator+(double,int)都可行，但是它们都需要类型转换，因此LongDouble的成员operator优先匹配

ex14_53

内置的operator+（int，double）是可行的，而3.14可以转换为int，然后再转换为SmallInt，所以SmallInt的成员operator+也是可行的，二者都需要类型转换，所以会产生二义性。应该进行如下修改：
double d = s1+Small(3..14)
